import tkinter as tk
from tkinter import messagebox
from struct import pack, unpack
from shutil import copy

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent

        self.f_name = u'face_diff.bin'

        # <create the rest of your GUI here>
        #frames
        self.frame_buttons = tk.Frame(parent)
        self.frame_buttons.grid(row=0, column=0, columnspan=5)
        self.frame_left = tk.Frame(parent)
        self.frame_left.grid(row=1, column=0)
        self.frame_middle = tk.Frame(parent)
        self.frame_middle.grid(row=1, column=1)
        self.frame_right = tk.Frame(parent)
        self.frame_right.grid(row=1, column=2, sticky="N")
        
        #buttons frame
        self.frame_buttons.grid_rowconfigure(0, minsize=50)
        self.btn_load = tk.Button(self.frame_buttons, text="Load face_diff.bin", command=self.load_diff_bin)
        self.btn_load.grid(row=0, column=1)
        self.frame_buttons.grid_columnconfigure(2, minsize=100)
        self.btn_save = tk.Button(self.frame_buttons, text="Save face_diff.bin", command=self.save_diff_bin, state=tk.DISABLED)
        self.btn_save.grid(row=0, column=3)

        #left frame, Block 2 data
        self.b2_label_heading = tk.Label(self.frame_left, text="Block 2 data - 33 sets of (x,y,z,0) items")
        self.b2_label_heading.grid(row=0, column=0, columnspan=5)
        
        self.b2_label_dummy = tk.Label(self.frame_left, text="", width=2)
        self.b2_label_x = tk.Label(self.frame_left, text="X", width=15)
        self.b2_label_y = tk.Label(self.frame_left, text="Y", width=15)
        self.b2_label_z = tk.Label(self.frame_left, text="Z", width=15)
        self.b2_label_0 = tk.Label(self.frame_left, text="0", width=15)
        self.b2_label_dummy.grid(row=2, column=0)
        self.b2_label_x.grid(row=2, column=1)
        self.b2_label_y.grid(row=2, column=2)
        self.b2_label_z.grid(row=2, column=3)
        self.b2_label_0.grid(row=2, column=4)

        self.b2_el_ind_list = []
        self.b2_el_x_list = []
        self.b2_el_y_list = []
        self.b2_el_z_list = []
        self.b2_el_0_list = []

        for i in range(33):
            self.b2_el_ind_list.append(tk.Label(self.frame_left, text="{0}.".format(i+1), width=2))
            self.b2_el_ind_list[i].grid(row=i+3, column=0)

            self.b2_el_x_list.append(tk.Entry(self.frame_left, width=15))
            self.b2_el_x_list[i].grid(row=i+3, column=1)

            self.b2_el_y_list.append(tk.Entry(self.frame_left, width=15))
            self.b2_el_y_list[i].grid(row=i+3, column=2)

            self.b2_el_z_list.append(tk.Entry(self.frame_left, width=15))
            self.b2_el_z_list[i].grid(row=i+3, column=3)

            self.b2_el_0_list.append(tk.Entry(self.frame_left, width=15))
            self.b2_el_0_list[i].grid(row=i+3, column=4)

        #middle spacer frame
        self.mid_label_spacer = tk.Label(self.frame_middle, text="             ")
        self.mid_label_spacer.grid()

        #right frame, Block 1 and Block 3 data
        self.b1_label_heading = tk.Label(self.frame_right, text="Block 1 data - 16 floating-point numbers")
        self.b1_label_heading.grid(row=0, column=0, columnspan=2)
        self.b1_label_heading2 = tk.Label(self.frame_right, text="Value")
        self.b1_label_heading2.grid(row=1, column=1)

        self.b1_el_ind_list = []
        self.b1_el_num_list = []

        for i in range(16):
            self.b1_el_ind_list.append(tk.Label(self.frame_right, text="{0}.".format(i+1), width=5))
            self.b1_el_ind_list[i].grid(row=i+2, column=0, sticky="E")

            self.b1_el_num_list.append(tk.Entry(self.frame_right, width=15))
            self.b1_el_num_list[i].grid(row=i+2, column=1, sticky="W")

        self.b3_label_heading = tk.Label(self.frame_right, text="Block 3 data - 6 sets of 8 floating-point numbers")
        self.b3_label_heading.grid(row=18, column=0, columnspan=9)
        self.b3_label_1 = tk.Label(self.frame_right, text="1", width=15)
        self.b3_label_2 = tk.Label(self.frame_right, text="2", width=15)
        self.b3_label_3 = tk.Label(self.frame_right, text="3", width=15)
        self.b3_label_4 = tk.Label(self.frame_right, text="4", width=15)
        self.b3_label_5 = tk.Label(self.frame_right, text="5", width=15)
        self.b3_label_6 = tk.Label(self.frame_right, text="6", width=15)
        self.b3_label_7 = tk.Label(self.frame_right, text="7", width=15)
        self.b3_label_8 = tk.Label(self.frame_right, text="8", width=15)
        self.b3_label_1.grid(row=19, column=1)
        self.b3_label_2.grid(row=19, column=2)
        self.b3_label_3.grid(row=19, column=3)
        self.b3_label_4.grid(row=19, column=4)
        self.b3_label_5.grid(row=19, column=5)
        self.b3_label_6.grid(row=19, column=6)
        self.b3_label_7.grid(row=19, column=7)
        self.b3_label_8.grid(row=19, column=8)

        self.b3_el_ind_list = []
        self.b3_el_1_list = []
        self.b3_el_2_list = []
        self.b3_el_3_list = []
        self.b3_el_4_list = []
        self.b3_el_5_list = []
        self.b3_el_6_list = []
        self.b3_el_7_list = []
        self.b3_el_8_list = []

        for i in range(6):
            self.b3_el_ind_list.append(tk.Label(self.frame_right, text="{0}.".format(i+1), width=2))
            self.b3_el_ind_list[i].grid(row=i+20, column=0,  sticky="E")

            self.b3_el_1_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_1_list[i].grid(row=i+20, column=1)

            self.b3_el_2_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_2_list[i].grid(row=i+20, column=2)

            self.b3_el_3_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_3_list[i].grid(row=i+20, column=3)

            self.b3_el_4_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_4_list[i].grid(row=i+20, column=4)

            self.b3_el_5_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_5_list[i].grid(row=i+20, column=5)

            self.b3_el_6_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_6_list[i].grid(row=i+20, column=6)

            self.b3_el_7_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_7_list[i].grid(row=i+20, column=7)

            self.b3_el_8_list.append(tk.Entry(self.frame_right, width=15))
            self.b3_el_8_list[i].grid(row=i+20, column=8)

        

    def load_diff_bin(self):
        if self.check_validity() == True:
            block1_of_16 = 0
            block2_of_33 = 0
            block3_of_6 = 0 
            with open(self.f_name, 'rb') as f:
                f.seek(8)
                block1_of_16 = f.read(0x40)
                f.seek(0xF0)
                block2_of_33 = f.read(0x10 * 33)
                f.seek(0x300)
                block3_of_6 = f.read()
                
                #populate block 1
                values = unpack("16f", block1_of_16)
                for i in range(16):
                    self.b1_el_num_list[i].delete(0, tk.END)
                    self.b1_el_num_list[i].insert(0, "{0:.10f}".format(values[i]))
                    
                #populate block 2
                for i in range(33):
                    vector = block2_of_33[i*0x10:(i+1)*0x10]
                    four_floats = unpack("4f", vector)
                    
                    self.b2_el_x_list[i].delete(0, tk.END)
                    self.b2_el_x_list[i].insert(0, "{0:.10f}".format(four_floats[0]))

                    self.b2_el_y_list[i].delete(0, tk.END)
                    self.b2_el_y_list[i].insert(0, "{0:.10f}".format(four_floats[1]))

                    self.b2_el_z_list[i].delete(0, tk.END)
                    self.b2_el_z_list[i].insert(0, "{0:.10f}".format(four_floats[2]))

                    self.b2_el_0_list[i].delete(0, tk.END)
                    self.b2_el_0_list[i].insert(0, "{0:.10f}".format(four_floats[3]))
                    self.b2_el_0_list[i].config(state=tk.DISABLED)

                #populate block 3
                for i in range(6):
                    vector = block3_of_6[i*0x20:(i+1)*0x20]
                    eight_floats = unpack("8f", vector)
                    
                    self.b3_el_1_list[i].delete(0, tk.END)
                    self.b3_el_1_list[i].insert(0, "{0:.10f}".format(eight_floats[0]))

                    self.b3_el_2_list[i].delete(0, tk.END)
                    self.b3_el_2_list[i].insert(0, "{0:.10f}".format(eight_floats[1]))

                    self.b3_el_3_list[i].delete(0, tk.END)
                    self.b3_el_3_list[i].insert(0, "{0:.10f}".format(eight_floats[2]))

                    self.b3_el_4_list[i].delete(0, tk.END)
                    self.b3_el_4_list[i].insert(0, "{0:.10f}".format(eight_floats[3]))

                    self.b3_el_5_list[i].delete(0, tk.END)
                    self.b3_el_5_list[i].insert(0, "{0:.10f}".format(eight_floats[4]))

                    self.b3_el_6_list[i].delete(0, tk.END)
                    self.b3_el_6_list[i].insert(0, "{0:.10f}".format(eight_floats[5]))

                    self.b3_el_7_list[i].delete(0, tk.END)
                    self.b3_el_7_list[i].insert(0, "{0:.10f}".format(eight_floats[6]))

                    self.b3_el_8_list[i].delete(0, tk.END)
                    self.b3_el_8_list[i].insert(0, "{0:.10f}".format(eight_floats[7]))
                    

            self.btn_save["state"]="normal"
        else:
            messagebox.showerror("ERROR", "Invalid structure of face_diff.bin")

    def check_validity(self):
        with open(self.f_name, 'rb') as f:
            if f.read(4).decode().upper() != "FACE":
                return False
            if unpack("<I", f.read(4))[0] != 0x05:
                return False
            f.seek(0x48)
            if unpack("<I", f.read(4))[0] != 0x21:
                return False
            if unpack("<I", f.read(4))[0] != 0x06:
                return False
        return True
            
    def save_diff_bin(self):
        copy(self.f_name, self.f_name+".bak")
        with open(self.f_name, 'rb+') as f:
            #save block 1
            f.seek(0x08)
            for i in range(16):
                float_value = pack("f", float(self.b1_el_num_list[i].get()))
                print(float(self.b1_el_num_list[i].get()))
                f.write(float_value)
            #save block 2
            f.seek(0xF0)
            for i in range(33):
                four_floats = pack("4f", float(self.b2_el_x_list[i].get()), float(self.b2_el_y_list[i].get()),
                                   float(self.b2_el_z_list[i].get()), 0)
                f.write(four_floats)
            #save block 3
            f.seek(0x300)
            for i in range(6):
                eight_floats = pack("8f", float(self.b3_el_1_list[i].get()), float(self.b3_el_2_list[i].get()),
                                    float(self.b3_el_3_list[i].get()), float(self.b3_el_4_list[i].get()),
                                    float(self.b3_el_5_list[i].get()), float(self.b3_el_6_list[i].get()),
                                    float(self.b3_el_7_list[i].get()), float(self.b3_el_8_list[i].get()) )
                f.write(eight_floats)

        messagebox.showinfo("INFO", "Changes saved to face_diff.bin")

if __name__ == "__main__":
    root = tk.Tk()
    root.title("PES 2018 face_diff.bin tester         (c) zlac, 2018")
    MainApplication(root) 
    root.mainloop()








